package charts; 
import charts.series.pies.PieLabel;
import flash.external.ExternalInterface;
import string.Utils;
import charts.series.Element;
import charts.series.pies.PieSliceContainer;
import charts.series.pies.DefaultPieProperties;
import global.Global;

import flash.display.Sprite;

//class Pie extends Base {
class Pie extends Sprite {

	var labels:Array<Dynamic>;
	var links:Array<Dynamic>;
	var colours:Array<Dynamic>;
	var gradientFill:String ; //toggle gradients
	var border_width:Int ;
	var label_line:Float;
	var easing:Dynamic;
	public var style:Dynamic;
	public var total_value:Int ;
	
	// new:
	var props:Properties;
	//
	
	public function new( json:Dynamic )
	{
		super();

		gradientFill = 'true';
		border_width = 1;
		total_value = 0;
		this.labels = new Array();
		this.links = new Array();
		this.colours = new Array();
		
		this.style = {
			colours:			["#900000", "#009000"]	// slices colours
		}
		
		Object_helper.merge_2( json, this.style );			
		
		for (colour in this.style.colours )
			this.colours.push( string.Utils.get_colour( colour ) );
			
		//
		//
		//
		this.props = new DefaultPieProperties(json);
		//
		//
		//
		
		this.label_line = 10;

		this.values = json.values;
		this.add_values();
	}
	
	
	//
	// Pie chart make is quite different to a normal make
	//
//	public override function add_values():Void {
	public function add_values():Void {
		//this.elements= new Array();
		
		//
		// Warning: this is our global singleton
		//
		var g:Global = Global.getInstance();
		
		var total:Int = 0;
		var slice_start:Float = this.props.get('start-angle');
		var i:Float;
		var val:Dynamic;
		
		for ( val in this.values ) {
			if( Std.is( val, Float) )
				total += val;
			else
				total += val.value;
		}
		this.total_value = total;
		
		i = 0;
		for ( val in this.values ) {
			
			var value:Int = Std.is( val, Float) ? cast( val, Float) : val.value;
			var slice_angle:Int = value*360/total;
			
			if( slice_angle >= 0 )
			{
				
				var t:String =  StringTools.replace(this.props.get('tip'),'#total#', NumberUtils.formatFloat( this.total_value ));
				t =  StringTools.replace(t,'#percent#', NumberUtils.formatFloat( value / this.total_value * 100 ) + '%');
			
				this.addChild(
					this.add_slice(
						i,
						slice_start,
						slice_angle,
						val,		// <-- NOTE: val (object) NOT value (a number)
						t,
						this.colours[(i % this.colours.length)]
						)
					);

				// TODO: fix this and remove
				// tmp.make_tooltip( this.key );
			}
			i++;
			slice_start += slice_angle;
		}
	}
	
	function add_slice( index:Float, start:Float, angle:Float, value:Dynamic, tip:String, colour:String ): PieSliceContainer {
		
			
		// Properties chain:
		//   pie-slice -> calculated-stuff -> pie
		//
		// calculated-stuff:
		var calculated_stuff:Properties = new Properties(
			{
				colour:				colour,		// <-- from the colour cycle array
				tip:				tip,		// <-- replaced the #total# & #percent# for this slice
				start:				start,		// <-- calculated
				angle:				angle		// <-- calculated
			},
			this.props );
		
		var tmp:Dynamic = {};			
		if ( Std.is( value, Float) )
			tmp.value = value;
		else
			tmp = value;
			
		var p:Properties = new Properties( tmp, calculated_stuff );
		
		// no user defined label?
		if ( !p.has('label') )
			p.set('label', p.get('value').toString());
		
		// Tr.acesPortMe( 'value', p.get('value'), p.get('label'), p.get('colour') );
		return new PieSliceContainer( index, p );
	}
	
	
//	public override function closest( x:Float, y:Float ): Dynamic {
	public function closest( x:Float, y:Float ): Dynamic {
		// PIE charts don't do closest to mouse tooltips
		return { Element:null, distance_x:0, distance_y:0 };
	}


//	public override function resize( sc:ScreenCoordsBase ): Void {
	public function resize( sc:ScreenCoordsBase ): Void {
		var radius:Int = this.style.radius;
		if (isNaN(radius)){
			radius = ( Math.min( sc.width, sc.height ) / 2.0 );
			var offsets:Dynamic = {top:0, right:0, bottom:0, left:0};
			trace("sc.width, sc.height, radius", sc.width, sc.height, radius);

			var i:Float;
			var sliceContainer:PieSliceContainer;

			// loop to gather and merge offsets
			for ( i in 0...this.numChildren) {
				sliceContainer = cast( this.getChildAt(i), PieSliceContainer);
				var pie_offsets:Dynamic = sliceContainer.get_radius_offsets();
				for (key in offsets) {
					if ( pie_offsets[key] > offsets[key] ) {
						offsets[key] = pie_offsets[key];
					}
				}
			}
			var vRadius:Int = radius;
			// Calculate minimum radius assuming the contraInt is vertical
			// Shrink radius by the largest top/bottom offset
			vRadius -= Math.max(offsets.top, offsets.bottom);
			// check to see if the left/right labels will fit
			if ((vRadius + offsets.left) > (sc.width / 2))
			{
				//radius -= radius + offsets.left - (sc.width / 2);
				vRadius = (sc.width / 2) - offsets.left;
			}
			if ((vRadius + offsets.right) > (sc.width / 2))
			{
				//radius -= radius + offsets.right - (sc.width / 2);
				vRadius = (sc.width / 2) - offsets.right;
			}

			// Make sure the radius is at least 10
			radius = Math.max(vRadius, 10);
		}

		var rightTopTicAngle:Int		= 720;
		var rightTopTicIdx:Int		= -1;
		var rightBottomTicAngle:Int	= -720;
		var rightBottomTicIdx:Int	= -1;

		var leftTopTicAngle:Int		= 720;
		var leftTopTicIdx:Int		= -1;
		var leftBottomTicAngle:Int	= -720;
		var leftBottomTicIdx:Int		= -1;

		// loop and resize
		for ( i in 0...this.numChildren)
		{
			sliceContainer = cast( this.getChildAt(i), PieSliceContainer);
			sliceContainer.pie_resize(sc, radius);

			// While we are looping through the children, we determine which
			// labels are the starting Points in each quadrant so that we
			// move the labels around to prevent overlaps
			var ticAngle:Int = sliceContainer.getTicAngle();
			if (ticAngle >= 270)
			{
				// Right side - Top
				if ((ticAngle < rightTopTicAngle) || (rightTopTicAngle <= 90))
				{
					rightTopTicAngle = ticAngle;
					rightTopTicIdx = i;
				}
				// Just in case no tics in Right-Bottom
				if ((rightBottomTicAngle < 0) ||
					((rightBottomTicAngle > 90) && (rightBottomTicAngle < ticAngle)))
				{
					rightBottomTicAngle = ticAngle;
					rightBottomTicIdx = i;
				}
			}
			else if (ticAngle <= 90)
			{
				// Right side - Bottom
				if ((ticAngle > rightBottomTicAngle) || (rightBottomTicAngle > 90))
				{
					rightBottomTicAngle = ticAngle;
					rightBottomTicIdx = i;
				}
				// Just in case no tics in Right-Top
				if ((rightTopTicAngle > 360) ||
					((rightTopTicAngle <= 90) && (ticAngle < rightBottomTicAngle)))
				{
					rightTopTicAngle = ticAngle;
					rightTopTicIdx = i;
				}
			}
			else if (ticAngle <= 180)
			{
			// Left side - Bottom
			if ((leftBottomTicAngle < 0) || (ticAngle < leftBottomTicAngle))
			{
				leftBottomTicAngle = ticAngle;
				leftBottomTicIdx = i;
			}
			// Just in case no tics in Left-Top
			if ((leftTopTicAngle > 360) || (leftTopTicAngle < ticAngle))
			{
				leftTopTicAngle = ticAngle;
				leftTopTicIdx = i;
			}
			}
			else
			{
				// Left side - Top
				if ((leftTopTicAngle > 360) || (ticAngle > leftTopTicAngle))
				{
					leftTopTicAngle = ticAngle;
					leftTopTicIdx = i;
				}
				// Just in case no tics in Left-Bottom
				if ((leftBottomTicAngle < 0) || (leftBottomTicAngle > ticAngle))
				{
					leftBottomTicAngle = ticAngle;
					leftBottomTicIdx = i;
				}
			}
		}

		// Make a clockwise pass on right side of pie trying to move
		// the labels so that they do not overlap
		var childIdx:Int = rightTopTicIdx;
		var yVal:Int = sc.top;
		var bDone:Bool = false;
		while ((childIdx >= 0) && (!bDone))
		{
			sliceContainer = cast( this.getChildAt(childIdx), PieSliceContainer);
			ticAngle = sliceContainer.getTicAngle();
			if ((ticAngle >= 270) || (ticAngle <= 90))
			{
				yVal = sliceContainer.moveLabelDown(sc, yVal);

				childIdx++;
				if (childIdx >= this.numChildren) childIdx = 0;

				bDone = (childIdx == rightTopTicIdx);
			}
			else
			{
				bDone = true;
			}
		}

		// Make a counter-clockwise pass on right side of pie trying to move
		// the labels so that they do not overlap
		childIdx = rightBottomTicIdx;
		yVal = sc.bottom;
		bDone = false;
		while ((childIdx >= 0) && (!bDone))
		{
			sliceContainer = cast( this.getChildAt(childIdx), PieSliceContainer);
			ticAngle = sliceContainer.getTicAngle();
			if ((ticAngle >= 270) || (ticAngle <= 90))
			{
				yVal = sliceContainer.moveLabelUp(sc, yVal);

				childIdx--;
				if (childIdx < 0) childIdx = this.numChildren - 1;

				bDone = (childIdx == rightBottomTicIdx);
			}
			else
			{
				bDone = true;
			}
		}

		// Make a clockwise pass on left side of pie trying to move
		// the labels so that they do not overlap
		childIdx = leftBottomTicIdx;
		yVal = sc.bottom;
		bDone = false;
		while ((childIdx >= 0) && (!bDone))
		{
			sliceContainer = cast( this.getChildAt(childIdx), PieSliceContainer);
			ticAngle = sliceContainer.getTicAngle();
			if ((ticAngle > 90) && (ticAngle < 270))
			{
				yVal = sliceContainer.moveLabelUp(sc, yVal);

				childIdx++;
				if (childIdx >= this.numChildren) childIdx = 0;

				bDone = (childIdx == leftBottomTicIdx);
			}
			else
			{
				bDone = true;
			}
		}

		// Make a counter-clockwise pass on left side of pie trying to move
		// the labels so that they do not overlap
		childIdx = leftTopTicIdx;
		yVal = sc.top;
		bDone = false;
		while ((childIdx >= 0) && (!bDone))
		{
			sliceContainer = cast( this.getChildAt(childIdx), PieSliceContainer);
			ticAngle = sliceContainer.getTicAngle();
			if ((ticAngle > 90) && (ticAngle < 270))
			{
				yVal = sliceContainer.moveLabelDown(sc, yVal);

				childIdx--;
				if (childIdx < 0) childIdx = this.numChildren - 1;

				bDone = (childIdx == leftTopTicIdx);
			}
			else
			{
				bDone = true;
			}
		}
	}
	
//	public override function toString():String {
	public function toString():String {
		return "Pie with "+ this.numChildren +" children";
	}
}
